/*
 * Copyright 2008-2023 dexian.vip. All rights reserved.
 * Support: http://www.dexian.vip
 * License: http://www.dexian.vip/license
 */

package vip.dexian.admin.freemarker.directive;

import vip.dexian.common.utils.FreeMarkerUtils;
import freemarker.core.Environment;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Freemarker 基础指令
 *
 * @author 挺好的 2023年05月30日 15:56
 */
public abstract class BaseDirective implements TemplateDirectiveModel {

    /**
     * 使用缓存
     */
    private static final String USE_CACHE_PARAMETER_NAME = "useCache";

    /**
     * id 参数名称
     */
    private static final String ID_PARAMETER_NAME = "id";

    /**
     * 数量参数名称
     */
    private static final String COUNT_PARAMETER_NAME = "count";

    /**
     * 是否使用缓存
     *
     * @param env
     *         上下文环境
     * @param params
     *         参数
     *
     * @return 默认返回true
     *
     * @throws freemarker.template.TemplateModelException
     *         {@link vip.dexian.common.utils.FreeMarkerUtils#getParameter(String, Class, java.util.Map)}
     * @throws IllegalArgumentException
     *         {@link vip.dexian.common.utils.FreeMarkerUtils#getParameter(String, Class, java.util.Map)}
     */
    protected boolean useCache (Environment env, Map <String, TemplateModel> params) throws TemplateModelException {
        Boolean useCache = FreeMarkerUtils.getParameter(BaseDirective.USE_CACHE_PARAMETER_NAME, Boolean.class, params);
        return useCache != null ? useCache : true;
    }

    /**
     * 获取ID
     *
     * @param params
     *         参数
     *
     * @return 如果不存在，返回null
     *
     * @throws freemarker.template.TemplateModelException
     *         {@link vip.dexian.common.utils.FreeMarkerUtils#getParameter(String, Class, java.util.Map)}
     * @throws IllegalArgumentException
     *         {@link vip.dexian.common.utils.FreeMarkerUtils#getParameter(String, Class, java.util.Map)}
     */
    protected Long getId (Map <String, TemplateModel> params) throws TemplateModelException {
        return FreeMarkerUtils.getParameter(BaseDirective.ID_PARAMETER_NAME, Long.class, params);
    }

    /**
     * 获取数量
     *
     * @param params
     *         参数
     *
     * @return 如果不存在，返回null
     *
     * @throws freemarker.template.TemplateModelException
     *         {@link vip.dexian.common.utils.FreeMarkerUtils#getParameter(String, Class, java.util.Map)}
     * @throws IllegalArgumentException
     *         {@link vip.dexian.common.utils.FreeMarkerUtils#getParameter(String, Class, java.util.Map)}
     */
    protected Integer getCount (Map <String, TemplateModel> params) throws TemplateModelException {
        return FreeMarkerUtils.getParameter(BaseDirective.COUNT_PARAMETER_NAME, Integer.class, params);
    }

    /**
     * 设置变量到freemarker local
     *
     * @param name
     *         变量名称
     * @param value
     *         变量值
     * @param env
     *         上下文环境
     * @param body
     *         指令内容体
     *
     * @throws freemarker.template.TemplateException
     * @throws java.io.IOException
     */
    protected void setLocalVariable (String name, Object value, Environment env, TemplateDirectiveBody body)
            throws TemplateException, IOException {

        TemplateModel preVariable = FreeMarkerUtils.getVariable(name, env);

        try {
            FreeMarkerUtils.setVariable(name, value, env);
            body.render(env.getOut());
        } finally {
            FreeMarkerUtils.setVariable(name, preVariable, env);
        }
    }

    /**
     * 设置变量到freemarker local
     *
     * @param variables
     *         存放变量的Map
     * @param env
     * @param body
     *
     * @throws freemarker.template.TemplateException
     * @throws java.io.IOException
     */
    protected void setLocalVariables (Map <String, Object> variables, Environment env, TemplateDirectiveBody body)
            throws TemplateException, IOException {

        Map <String, Object> preVariables = new HashMap <>();
        for (String name : variables.keySet()) {
            TemplateModel preVariable = FreeMarkerUtils.getVariable(name, env);
            preVariables.put(name, preVariable);
        }

        try {
            FreeMarkerUtils.setVariables(variables, env);
            body.render(env.getOut());
        } finally {
            FreeMarkerUtils.setVariables(preVariables, env);
        }
    }
}
